/*!	 action_system.h
**	 Template Header
**
**	Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
**
**	This package is free software; you can redistribute it and/or
**	modify it under the terms of the GNU General Public License as
**	published by the Free Software Foundation; either version 2 of
**	the License, or (at your option) any later version.
**
**	This package is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
**	General Public License for more details.
**
*/

#ifndef __SYNFIGAPP_ACTIONSYSTEM_H
#define __SYNFIGAPP_ACTIONSYSTEM_H

#include "action.h"
#include <sigc++/sigc++.h>
#include <ETL/handle>
#include <synfig/canvas.h>
#include "uimanager.h"

namespace synfigapp
{

class CanvasInterface;

namespace Action
{

class System;

// Passive action grouping class
class PassiveGrouper
{
    etl::loose_handle<System> instance_;
    synfig::String name_;
    bool redraw_requested_;
    int depth_;
    etl::handle<CanvasInterface> canvas_interface_;
    bool finished_;
public:

    PassiveGrouper(etl::loose_handle<System> instance_, synfig::String name_);

    ~PassiveGrouper();

    const synfig::String &get_name()const
    {
        return name_;
    }

    void set_name(const synfig::String &x)
    {
        name_ = x;
    }

    etl::loose_handle<System> get_instance()
    {
        return instance_;
    }

    void request_redraw(etl::handle<CanvasInterface>);

    etl::handle<Action::Group> finish();

    void cancel();

    void inc_depth()
    {
        depth_++;
    }

    void dec_depth()
    {
        depth_--;
    }

    const int &get_depth()const
    {
        return depth_;
    }
}; // END of class Action::PassiveGrouper

typedef std::list< etl::handle<Action::Undoable> > Stack;

class System : public etl::shared_object, public sigc::trackable
{
    friend class PassiveGrouper;



public:



public:



private:

    Stack undo_action_stack_;
    Stack redo_action_stack_;

    synfig::String most_recent_action_name_;

    std::list<PassiveGrouper*> group_stack_;

    sigc::signal<void, bool> signal_undo_status_;
    sigc::signal<void, bool> signal_redo_status_;
    sigc::signal<void, etl::handle<Action::Undoable> > signal_new_action_;
    sigc::signal<void> signal_undo_stack_cleared_;
    sigc::signal<void> signal_redo_stack_cleared_;
    sigc::signal<void> signal_undo_;
    sigc::signal<void> signal_redo_;
    sigc::signal<void, etl::handle<Action::Undoable> > signal_action_status_changed_;

    mutable sigc::signal<void, bool> signal_unsaved_status_changed_;

    // If this is non-zero, then the changes have not yet been saved.
    mutable int action_count_;

    etl::handle<UIInterface> ui_interface_;

    bool clear_redo_stack_on_new_action_;



private:

    bool undo_(etl::handle<UIInterface> uim);
    bool redo_(etl::handle<UIInterface> uim);



private:



public:

    System();
    ~System();



    synfig::String get_most_recent_action_name()
    {
        return most_recent_action_name_;
    }

    bool get_clear_redo_stack_on_new_action()const
    {
        return clear_redo_stack_on_new_action_;
    }

    void set_clear_redo_stack_on_new_action(bool x)
    {
        clear_redo_stack_on_new_action_ = x;
    }

    bool perform_action(etl::handle<Action::Base> action);

    bool set_action_status(etl::handle<Action::Undoable> action, bool x);

    const Stack &undo_action_stack()const
    {
        return undo_action_stack_;
    }

    const Stack &redo_action_stack()const
    {
        return redo_action_stack_;
    }

    // Undoes the last action
    bool undo();

    // Redoes the last undone action
    bool redo();

    // Clears the undo stack.
    void clear_undo_stack();

    // Clears the redo stack.
    void clear_redo_stack();

    // Increments the action counter
    /*! \note You should not have to call this under normal circumstances.
    **	\see dec_action_count(), reset_action_count(), get_action_count() */
    void inc_action_count()const;

    // Decrements the action counter
    /*! \note You should not have to call this under normal circumstances.
    **	\see inc_action_count(), reset_action_count(), get_action_count() */
    void dec_action_count()const;

    // Resets the action counter
    /*! \note You should not have to call this under normal circumstances.
    **	\see inc_action_count(), dec_action_count(), get_action_count() */
    void reset_action_count()const;

    // Returns the number of actions performed since last save.
    /*!	\see inc_action_count(), dec_action_count(), reset_action_count() */
    int get_action_count()const
    {
        return action_count_;
    }

    void set_ui_interface(const etl::handle<UIInterface> &uim)
    {
        assert(uim);
        ui_interface_ = uim;
    }
    void unset_ui_interface()
    {
        ui_interface_ = new DefaultUIInterface();
    }
    const etl::handle<UIInterface> &get_ui_interface()
    {
        return ui_interface_;
    }



public:

    sigc::signal<void, bool>& signal_unsaved_status_changed()
    {
        return signal_unsaved_status_changed_;
    }

    sigc::signal<void, bool>& signal_undo_status()
    {
        return signal_undo_status_;
    }

    sigc::signal<void, bool>& signal_redo_status()
    {
        return signal_redo_status_;
    }

    sigc::signal<void>& signal_undo_stack_cleared()
    {
        return signal_undo_stack_cleared_;
    }

    sigc::signal<void>& signal_redo_stack_cleared()
    {
        return signal_redo_stack_cleared_;
    }

    sigc::signal<void>& signal_undo()
    {
        return signal_undo_;
    }

    sigc::signal<void>& signal_redo()
    {
        return signal_redo_;
    }

    //	Called whenever an undoable action is processed and added to the stack.
    sigc::signal<void, etl::handle<Action::Undoable> >& signal_new_action()
    {
        return signal_new_action_;
    }

    sigc::signal<void, etl::handle<Action::Undoable> >& signal_action_status_changed()
    {
        return signal_action_status_changed_;
    }

}; // END of class Action::System

}; // END of namespace synfigapp::Action
}; // END of namespace synfigapp

#endif